(cond-expand
 (modules (import (only (chibi test) test-begin test-assert test test-error test-end)))
 (else #f))

(import (scheme base))
(import (scheme write))
(import (clock tai-to-utc-offset))

(test-begin "(clock tai-to-utc-offset)")

(test-assert (eqv? (tai-to-utc-offset-at-utc-day 15523) 35))
(test-assert (eqv? (tai-to-utc-offset-at-utc-day 15522) 35))
(test-assert (eqv? (tai-to-utc-offset-at-utc-day 15521) 34))
(test-assert (eqv? (tai-to-utc-offset-at-utc-day 14246) 34))
(test-assert (eqv? (tai-to-utc-offset-at-utc-day 14245) 34))
(test-assert (eqv? (tai-to-utc-offset-at-utc-day 14244) 33))
(test-assert (eqv? (tai-to-utc-offset-at-utc-day   731) 10))
(test-assert (eqv? (tai-to-utc-offset-at-utc-day   730) 10))

;; The next block of tests assume inexact arithmetic is at least uniformly
;; inexact. That is, the calculations performed here and those in the
;; actual library should give the same inexact results for the same
;; arguments.

(test-assert (eqv? (tai-to-utc-offset-at-utc-day   365) ; 1971-01-01 UTC
                   (+ 4.2131700 (* (- 40952 39126) 0.002592))))
(test-assert (eqv? (tai-to-utc-offset-at-utc-day     0) ; 1970-01-01 UTC
                   (+ 4.2131700 (* (- 40587 39126) 0.002592))))
(test-assert (eqv? (tai-to-utc-offset-at-utc-day  -365) ; 1969-01-01 UTC
                   (+ 4.2131700 (* (- 40222 39126) 0.002592))))
(test-assert (eqv? (tai-to-utc-offset-at-utc-day  -731) ; 1968-01-01 UTC
                   (+ 4.3131700 (* (- 39856 39126) 0.002592))))
(test-assert (eqv? (tai-to-utc-offset-at-utc-day -1096) ; 1967-01-01 UTC
                   (+ 4.3131700 (* (- 39491 39126) 0.002592))))
(test-assert (eqv? (tai-to-utc-offset-at-utc-day -1461) ; 1966-01-01 UTC
                   (+ 4.3131700 (* (- 39126 39126) 0.002592))))
(test-assert (eqv? (tai-to-utc-offset-at-utc-day -1826) ; 1965-01-01 UTC
                   (+ 3.540130 (* (- 38761 38761) 0.002592))))
(test-assert (eqv? (tai-to-utc-offset-at-utc-day -2192) ; 1964-01-01 UTC
                   (+ 3.240130 (* (- 38395 38761) 0.001296))))
(test-assert (eqv? (tai-to-utc-offset-at-utc-day -2557) ; 1963-01-01 UTC
                   (+ 1.845858 (* (- 38030 37665) 0.0011232))))
(test-assert (eqv? (tai-to-utc-offset-at-utc-day -2922) ; 1962-01-01 UTC
                   (+ 1.845858 (* (- 37665 37665) 0.0011232))))
(test-assert (eqv? (tai-to-utc-offset-at-utc-day -3287) ; 1961-01-01 UTC
                   (+ 1.422818 (* (- 37300 37300) 0.001296))))

(test-error (tai-to-utc-offset-at-utc-day -3288)) ; 1960-12-31

(test-assert
 (eqv? (tai-to-utc-offset-at-tai-second (+ (* 86400 15522) 35 +1)) 35))
(test-assert
 (eqv? (tai-to-utc-offset-at-tai-second (+ (* 86400 15522) 35  0)) 35))
(test-assert
 (eqv? (tai-to-utc-offset-at-tai-second (+ (* 86400 15522) 35 -1)) 34))
(test-assert
 (eqv? (tai-to-utc-offset-at-tai-second (+ (* 86400 14245) 34 +1)) 34))
(test-assert
 (eqv? (tai-to-utc-offset-at-tai-second (+ (* 86400 14245) 34  0)) 34))
(test-assert
 (eqv? (tai-to-utc-offset-at-tai-second (+ (* 86400 14245) 34 -1)) 33))
(test-assert
 (eqv? (tai-to-utc-offset-at-tai-second (+ (* 86400   730) 10 +1)) 10))
(test-assert
 (eqv? (tai-to-utc-offset-at-tai-second (+ (* 86400   730) 10  0)) 10))

(define (approx= x y)
  (< (abs (- x y)) 1e-12))

(define (utc-day-to-tai-second utc-day)
  (+ (* utc-day 24 60 60) (tai-to-utc-offset-at-utc-day utc-day)))

(define-syntax test-tai-to-utc-offset-at-tai-second
  (syntax-rules ()
    ((tai-to-utc-offset-at-tai-second utc-day)
     (test-assert
      (approx= (tai-to-utc-offset-at-tai-second (utc-day-to-tai-second utc-day))
               (tai-to-utc-offset-at-utc-day utc-day))))))

(test-tai-to-utc-offset-at-tai-second   365) ; 1971-01-01 UTC
(test-tai-to-utc-offset-at-tai-second     0) ; 1970-01-01 UTC
(test-tai-to-utc-offset-at-tai-second  -365) ; 1969-01-01 UTC
(test-tai-to-utc-offset-at-tai-second  -731) ; 1968-01-01 UTC
(test-tai-to-utc-offset-at-tai-second -1096) ; 1967-01-01 UTC
(test-tai-to-utc-offset-at-tai-second -1461) ; 1966-01-01 UTC
(test-tai-to-utc-offset-at-tai-second -1826) ; 1965-01-01 UTC
(test-tai-to-utc-offset-at-tai-second -2192) ; 1964-01-01 UTC
(test-tai-to-utc-offset-at-tai-second -2557) ; 1963-01-01 UTC
(test-tai-to-utc-offset-at-tai-second -2922) ; 1962-01-01 UTC
(test-tai-to-utc-offset-at-tai-second -3287) ; 1961-01-01 UTC
(test-error (tai-to-utc-offset-at-tai-second
             (- (utc-day-to-tai-second -3287) 86400))) ; 1960-12-31 UTC

(define-syntax test-strict-tai-to-utc-offset-at-tai-second
  (syntax-rules ()
    ((strict-tai-to-utc-offset-at-tai-second utc-day)
     (test-assert
      (approx= (strict-tai-to-utc-offset-at-tai-second (utc-day-to-tai-second utc-day))
               (tai-to-utc-offset-at-utc-day utc-day))))))

(test-strict-tai-to-utc-offset-at-tai-second   365) ; 1971-01-01 UTC
(test-strict-tai-to-utc-offset-at-tai-second     0) ; 1970-01-01 UTC
(test-strict-tai-to-utc-offset-at-tai-second  -365) ; 1969-01-01 UTC
(test-strict-tai-to-utc-offset-at-tai-second  -731) ; 1968-01-01 UTC
(test-strict-tai-to-utc-offset-at-tai-second -1096) ; 1967-01-01 UTC
(test-strict-tai-to-utc-offset-at-tai-second -1461) ; 1966-01-01 UTC
(test-strict-tai-to-utc-offset-at-tai-second -1826) ; 1965-01-01 UTC
(test-strict-tai-to-utc-offset-at-tai-second -2192) ; 1964-01-01 UTC
(test-strict-tai-to-utc-offset-at-tai-second -2557) ; 1963-01-01 UTC
(test-strict-tai-to-utc-offset-at-tai-second -2922) ; 1962-01-01 UTC
(test-strict-tai-to-utc-offset-at-tai-second -3287) ; 1961-01-01 UTC
(test-error (strict-tai-to-utc-offset-at-tai-second
             (- (utc-day-to-tai-second -3287) 86400))) ; 1960-12-31 UTC

;; Undefined just before 1972-01-01 UTC.
(test-error (strict-tai-to-utc-offset-at-tai-second
             (- (utc-day-to-tai-second 730) 0.05)))

;; Multiply defined just after 1968-02-01 UTC.
(test-error (strict-tai-to-utc-offset-at-tai-second
             (+ (utc-day-to-tai-second -700) 0.05)))

(test-end "(clock tai-to-utc-offset)")
